package cn.snmp.mutual.common.tools;

import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Attr;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import cn.snmp.mutual.data.ObjService;
import cn.snmp.mutual.data.XmlService;
import cn.snmp.mutual.util.DumpUtil;
/**
 * @since 2018.9.1
 * @author dengkn
 * XmlFile   XML NODE解析工具
 */
@Slf4j
public class XmlFile {
	public static final String NODE_VALUE = "NODE_VALUE";
	private boolean xmlbOptimizeXmlFormat = false;
	private boolean xmlbIgnoringComments = false;
	private boolean xmlBIgnoringElementContentWhitespace = false;
	private String xmlCopyRightInfo;
	private String xmlStrFilename;
	private Document xmlDocument;
	
	
	public XmlFile() {
		this.xmlStrFilename = null;
		this.xmlCopyRightInfo = "";
		this.xmlDocument = null;
	}

	public XmlFile(String fileName) {
		this.xmlStrFilename = fileName;
		this.xmlCopyRightInfo = "";
		this.xmlDocument = null;
		try {
			this.decode(fileName);
		} catch (Exception arg2) {
		
		}

	}

	public XmlFile(XmlService obj) {
		this.xmlStrFilename = null;
		this.xmlDocument = null;
		this.xmlCopyRightInfo = "";

		try {
			this.createDocument();
			this.setRootNode(this.xmlService2Node(obj));
		} catch (Exception arg2) {
			
		}

	}

	public void setCopyRight(String copyRight) {
		this.xmlCopyRightInfo = copyRight;
	}

	private void setOptimizeXmlFormat(boolean optimizeXmlFormat) {
		this.xmlbOptimizeXmlFormat = optimizeXmlFormat;
	}

	public void setIgnoringComments(boolean ignoringComments) {
		this.xmlbIgnoringComments = ignoringComments;
	}

	public boolean getIgnoringComments() {
		return this.xmlbIgnoringComments;
	}

	public void setIgnoringElementContentWhitespace(boolean ignoringElementContentWhitespace) {
		this.xmlBIgnoringElementContentWhitespace = ignoringElementContentWhitespace;
	}

	public boolean setIgnoringElementContentWhitespace() {
		return this.xmlBIgnoringElementContentWhitespace;
	}

	public URL getURL(String s) {
		Component component = new Component() {
		};
		ClassLoader loader = (ClassLoader) component.getClass().getClassLoader();
		URL url = loader.getResource(s);
		if (url == null) {
			DumpUtil.debug("Cannot find resource [" + s + "].");
		}
		return url;
	}

	public Document decode(String fileName) {
		return this.decode(this.getURL(fileName));
	}


	public Document decode(URL url) {
		if (url != null) {
			DocumentBuilderFactory documentbuilderfactory = DocumentBuilderFactory.newInstance();
			documentbuilderfactory.setNamespaceAware(true);
			documentbuilderfactory.setIgnoringComments(this.xmlbIgnoringComments);
			documentbuilderfactory.setIgnoringElementContentWhitespace(this.xmlBIgnoringElementContentWhitespace);
			documentbuilderfactory.setCoalescing(true);

			try {
				URLConnection exception = url.openConnection();
				exception.connect();
				DocumentBuilder documentbuilder = documentbuilderfactory.newDocumentBuilder();
				this.xmlDocument = documentbuilder.parse(exception.getInputStream());
		
				return this.xmlDocument;
			} catch (Exception arg4) {
						return null;
			}
		} else {
			DumpUtil.debug("Fail to decode the file : " + url.toString() + " the URL is null");
			return null;
		}
	}

	public void createDocument() {
		DocumentBuilderFactory documentbuilderfactory = DocumentBuilderFactory.newInstance();
		documentbuilderfactory.setNamespaceAware(true);
		documentbuilderfactory.setIgnoringComments(this.xmlbIgnoringComments);
		documentbuilderfactory.setIgnoringElementContentWhitespace(this.xmlBIgnoringElementContentWhitespace);
		documentbuilderfactory.setCoalescing(true);

		try {
			DocumentBuilder exception = documentbuilderfactory.newDocumentBuilder();
			this.xmlDocument = exception.newDocument();
		} catch (Exception arg2) {
			DumpUtil.debug("Fail to create the file...");
		}

	}

	public Document getDocument() {
		return this.xmlDocument == null ? null : this.xmlDocument;
	}

	public Node getRootNode() {
		return this.xmlDocument == null ? null : this.xmlDocument.getDocumentElement();
	}

	public void setRootNode(Node rootNode) {
		if (this.xmlDocument.hasChildNodes()) {
			Node comment = this.xmlDocument.getFirstChild();

			do {
				if (comment.getNodeType() == 1) {
					this.xmlDocument.removeChild(comment);
					break;
				}

				comment = comment.getNextSibling();
			} while (comment != null);
		}

		if (this.xmlbOptimizeXmlFormat && !"".equals(this.xmlCopyRightInfo)) {
			Comment comment1 = this.xmlDocument.createComment(this.xmlCopyRightInfo);
			this.xmlDocument.appendChild(comment1);
		}

		this.xmlDocument.appendChild(rootNode);
	}

	public Node xmlService2Node(XmlService xmlObj) {
		Object node = null;
		String nodeValue = null;
		if (xmlObj == null) {
			return (Node) node;
		} else {
			int nodeType = xmlObj.getNodeType();
			switch (nodeType) {
				case 1 :
					node = getXMlNode1Case1(xmlObj);
					break;
				case 2 :
				case 3 :
					nodeValue = xmlObj.getStringValue(NODE_VALUE);
					Text text = this.xmlDocument.createTextNode(nodeValue);
					node = text;
					break;
				case 4 :
				case 5 :
				case 6 :
				case 7 :
				case 8 :
					nodeValue = xmlObj.getStringValue(NODE_VALUE);
					Comment comment = this.xmlDocument.createComment(nodeValue);
					node = comment;
					break;
				case 9 :
				case 10 :
				case 11 :
				case 12 :
				default :
					break;
			}

			return (Node) node;
		}
	}

	private Node getXMlNode1Case1(XmlService xmlObj) {
		String className = xmlObj.getNodeName();
		Element element = this.xmlDocument.createElement(className);
		for(Object key :xmlObj.getCurrentHashMap().entrySet()) {
			element.setAttribute((String)key, (String) xmlObj.getCurrentHashMap().get((String)key));
		}
		LinkedList<?> arg15 = xmlObj.getCurrentVector();
		int vectorSize = arg15.size();

		for (int arg16 = 0; arg16 < vectorSize; ++arg16) {
			XmlService arg17 = (XmlService) arg15.get(arg16);
			arg17.setNodeLevel(xmlObj.getNodeLevel() + 1);
			if (this.xmlbOptimizeXmlFormat && arg17.getNodeType() != 3) {
				StringBuilder chileNode = new StringBuilder("\n");
				for (int addText = 0; addText < xmlObj.getNodeLevel(); ++addText) {
					chileNode = chileNode.append("\t");
				}

				Text arg19 = this.xmlDocument.createTextNode(chileNode.toString());
				element.appendChild(arg19);
			}
			Node arg18 = this.xmlService2Node(arg17);
			element.appendChild(arg18);
			if (this.xmlbOptimizeXmlFormat && arg17.getNodeType() != 3 && arg16 == vectorSize - 1) {
				StringBuilder textNodeStr = new StringBuilder("\n");
				for (int text1 = 0; text1 < xmlObj.getNodeLevel() - 1; ++text1) {
					textNodeStr = textNodeStr.append("\t");
				}
				Text arg21 = this.xmlDocument.createTextNode(textNodeStr.toString());
				element.appendChild(arg21);
			}
		}
		return element;
	}
	
	public XmlService node2XmlService(Node node) {
		XmlService objservice = new XmlService(node.getNodeName());
		objservice.setNodeType(node.getNodeType());
		NamedNodeMap namednodemap = node.getAttributes();
		int k;
		if (namednodemap != null) {
			int nodeList = namednodemap.getLength();
			for (k = 0; k < nodeList; ++k) {
				Attr l = (Attr) namednodemap.item(k);
				objservice.setValue(l.getNodeName(), l.getNodeValue());
			}
		}
		if (node.hasChildNodes()) {
			NodeList arg14 = node.getChildNodes();
			k = arg14.getLength();

			for (int arg15 = 0; arg15 < k; ++arg15) {
				Node childNode = arg14.item(arg15);
				short nodeType = childNode.getNodeType();
				switch (nodeType) {
					case 1 :
						XmlService childObjService = null;
						childObjService = this.node2XmlService(childNode);
						if (childObjService == null) {
							return objservice;
						}
						objservice.addContainedObject(childObjService);
						break;
					case 2 :
					case 3 :
						getXMlNode2Case3(childNode, objservice);
						break;
					case 4 :
					case 5 :
					case 6 :
					case 7 :
					case 8 :
						XmlService commentNodeService = new XmlService(childNode.getNodeName());
						commentNodeService.setNodeType(childNode.getNodeType());
						commentNodeService.setValue(NODE_VALUE, childNode.getNodeValue());
						objservice.addContainedObject(commentNodeService);
						break;
					case 9 :
					case 10 :
					case 11 :
					case 12 :
					default :
						break;
				}
			}
		}

		return objservice;
	}

	private void getXMlNode2Case3(Node childNode, XmlService objservice) {
		String nodeValue = childNode.getNodeValue();
		int strlength = nodeValue.length();
		int arg16;
		for (arg16 = 0; arg16 < strlength; ++arg16) {
			char textNodeService = nodeValue.charAt(arg16);
			if (textNodeService != 13 && textNodeService != 10 && textNodeService != 32
					&& textNodeService != 9) {
				break;
			}
		}
		if (arg16 != strlength) {
			XmlService arg17 = new XmlService(childNode.getNodeName());
			arg17.setNodeType(childNode.getNodeType());
			arg17.setValue(NODE_VALUE, nodeValue);
			objservice.addContainedObject(arg17);
		}
	}
	
	public void optimizeXmlFormat() {
		this.setOptimizeXmlFormat(true);
		XmlService rootObj = this.node2XmlService(this.getRootNode());
		rootObj.setNodeLevel(1);
		Node rootNode = this.xmlService2Node(rootObj);
		this.setRootNode(rootNode);
		this.setOptimizeXmlFormat(false);
	}

	public boolean redirect(String strFilename) {
		if (strFilename == null) {
			strFilename = this.xmlStrFilename;
		}

		try {
			TransformerFactory iOException = TransformerFactory.newInstance();
			Transformer transformer = iOException.newTransformer();
			DOMSource domsource = new DOMSource(this.xmlDocument);
			StreamResult streamresult = new StreamResult(new File(strFilename));
			transformer.setOutputProperty("encoding", "GB2312");
			transformer.setOutputProperty("indent", "yes");
			transformer.transform(domsource, streamresult);
			if (streamresult != null) {
				streamresult.getOutputStream().close();
			}

			return true;
		} catch (TransformerConfigurationException arg5) {
			DumpUtil.debug(arg5);
			return false;
		} catch (TransformerException arg6) {
			DumpUtil.debug(arg6);
			return false;
		} catch (IOException arg7) {
			DumpUtil.debug(arg7);
			return false;
		}
	}

	public boolean redirect(String strFilename, String strEncoding) {
		if (strFilename == null) {
			strFilename = this.xmlStrFilename;
		}

		try {
			TransformerFactory transformerexception = TransformerFactory.newInstance();
			Transformer transformer = transformerexception.newTransformer();
			DOMSource domsource = new DOMSource(this.xmlDocument);
			StreamResult streamresult = new StreamResult(new File(strFilename));
			transformer.setOutputProperty("encoding", strEncoding);
			transformer.setOutputProperty("indent", "yes");
			transformer.transform(domsource, streamresult);
			return true;
		} catch (TransformerConfigurationException arg6) {
			DumpUtil.debug(arg6);
			return false;
		} catch (TransformerException arg7) {
			DumpUtil.debug(arg7);
			return false;
		}
	}

	public static ObjService getXmlFile(String xmlFileName) {
		try {
			XmlFile e = new XmlFile(xmlFileName);
			XmlService xmlService = e.node2XmlService(e.getRootNode());
			return XmlService.xmlService2ObjService(xmlService);
		} catch (Exception arg2) {
			DumpUtil.debug("Parse XML File " + xmlFileName + " Error.");
			return null;
		}
	}

	public static boolean redirect(ObjService xmlDocument, String xmlFileName) {
		return false;
	}

	public static void main(String[] args) {
		ObjService test = new ObjService("test");
		test.setValue("kkk", "aasdfadsfas");
		test.setValue("dddd", "adasd");
		ObjService c = new ObjService("Child");
		c.setValue("c", "1");
		test.addContainedObject(c);
		XmlService obj = XmlService.objService2XmlService(test);
		XmlFile utilnew = new XmlFile(obj);
		utilnew.optimizeXmlFormat();
		utilnew.redirect("c:\\3.xml");
	}
}